#include "AbstractAdvancedModel.h"

AbstractAdvancedModel::AbstractAdvancedModel()
{
	//Init AABB to something useless. 
	aabbL.Center = XMFLOAT3(0,0,0);
	aabbL.Extents = XMFLOAT3(0,0,0);

	//Init world data
	position = XMFLOAT3(0,0,0);
	rotation = XMFLOAT3(0,0,0);
	scaling = XMFLOAT3(1.0f, 1.0f, 1.0f);
	CreateWorldMatrix();

	//Not inited as of yet... 
	isInit = false; 

	//Subclass doesnt manage culling by default
	subclassManagesFrustumCulling = false;
}

AbstractAdvancedModel::~AbstractAdvancedModel()
{}

void AbstractAdvancedModel::GenerateAABB()
{
	//Ensure we have some data to play with.  
	assert(sysCopyVerts.size() > 0);

	//AABB - min and max xyz values. 
	XMFLOAT3 min = XMFLOAT3(+MathHelper::Infinity, +MathHelper::Infinity, +MathHelper::Infinity);
	XMFLOAT3 max = XMFLOAT3(-MathHelper::Infinity, -MathHelper::Infinity, -MathHelper::Infinity);

	XMVECTOR vMin = XMLoadFloat3(&min);
	XMVECTOR vMax = XMLoadFloat3(&max);

	//Loop through system copy of positions
	for (unsigned i = 0; i < sysCopyVerts.size(); i++)
	{
		//Load position in to a vector.
		XMVECTOR point = XMLoadFloat3(&sysCopyVerts[i]);

		//Update min/max
		vMin = XMVectorMin(vMin, point);
		vMax = XMVectorMax(vMax, point);
	}

	//Work out center point and the extents
	XMVECTOR center = 0.5f * (vMin + vMax);
	XMVECTOR extend = 0.5f * (vMax - vMin);

	//Convert to XMFLOAT3 format. 
	XMFLOAT3 fC;
	XMFLOAT3 fE;
	XMStoreFloat3(&fC, center);
	XMStoreFloat3(&fE, extend);

	//update AABB structure.
	aabbL.Center = fC;
	aabbL.Extents = fE;
}

void AbstractAdvancedModel::CreateWorldMatrix()
{
	//Create world matrix. 
	XMMATRIX trans = XMMatrixTranslation(position.x, position.y, position.z);
	XMMATRIX rotationX = XMMatrixRotationX(rotation.x);
	XMMATRIX rotationY = XMMatrixRotationY(rotation.y);
	XMMATRIX rotationZ = XMMatrixRotationZ(rotation.z);
	XMMATRIX rotationM = (rotationX * rotationY) * rotationZ;
	XMMATRIX scaleM = XMMatrixScaling(scaling.x, scaling.y, scaling.z);
	XMMATRIX world = (scaleM * rotationM) * trans;

	//Store in to newMaterial
	XMStoreFloat4x4(&worldMatrix, world);
}

void AbstractAdvancedModel::SetWorldPosition(XMFLOAT3 pos)
{
	//store position
	position = pos;

	//Create world matrix.
	CreateWorldMatrix();
}

void AbstractAdvancedModel::SetWorldRotation(XMFLOAT3 rot)
{
	//store rotation
	rotation = rot;
	
	//Create world matrix.
	CreateWorldMatrix();
}

void AbstractAdvancedModel::SetWorldScale(XMFLOAT3 scale)
{
	//store scaling factor
	scaling = scale;
	
	//Create world matrix.
	CreateWorldMatrix();
}

void AbstractAdvancedModel::SetWorldMatrix(XMFLOAT3 pos, XMFLOAT3 rot, XMFLOAT3 scale)
{
	//Store pos, rot and scale
	position = pos;
	rotation = rot;
	scaling = scale;

	//Create world matrrix.
	CreateWorldMatrix();
}

void AbstractAdvancedModel::OnBatchAdd(GraphicsInterface* sharedGraphicsInterface)
{}

XNA::AxisAlignedBox AbstractAdvancedModel::CalculateWorldSpaceAABB()
{
	XNA::AxisAlignedBox aabbW;

	//Convert from float3 to XMVECTOR
	XMVECTOR r = XMLoadFloat3(&rotation);
	XMVECTOR t = XMLoadFloat3(&position);

	//Transform and return
	XNA::TransformAxisAlignedBox(&aabbW, &aabbL, scaling.x, r, t);

	return aabbW;
}